local Bidding = AspireML:NewModule("Bidding", "AceEvent-3.0", "AceConsole-3.0", "AceTimer-3.0")


function Bidding:OnInitialize()
	
	-- initialize new bid queue
	self.bidqueue = {}
	
	
end

function Bidding:OnEnable()
	
	self:RegisterMessage( "AspireML_StartBid", "StartBid" );
	self:RegisterMessage( "AspireML_StartRoll", "StartRoll" );
	self:RegisterMessage( "AspireML_StartRaidRoll", "StartRaidRoll" );
	self:RegisterMessage( "AspireML_ListBids", "ListBids" );
	self:RegisterMessage( "AspireML_CloseBid", "CloseBid" );	
	self:ScheduleRepeatingTimer( "BidQueueTimer", 0.3 );
end

function Bidding:BidQueueTimer()

	for unitname, message in pairs( self.bidqueue) do	
		if unitname ~= nil and message ~= nil then			
			self.bidqueue[unitname] = nil;
			self:HandleBidWhisper( "EVENT_WHISPER", message, unitname );	
		end
	end
end

function Bidding:StartBid( arg1, arg2 )

	-- clear current bids
	Bidding:CloseActiveStates()

	-- open
	AspireML.biditem = AspireML:ParseItem(arg2)
	AspireML.mode = "bid"
	
	if AspireML.masterlooter then 
	
		self:RegisterEvent("CHAT_MSG_WHISPER", "HandleBidWhisper");		
		SendChatMessage( "Bidding on: " .. arg2, "RAID_WARNING", nil);
	
		-- Short line of text pls, this is going to be in raid chat all the time. The shorter the better.
		SendChatMessage(("Whisper me: \"[CURRENT ITEM]\" or \"offspec\"."), "RAID", nil)
	end
end

-- handle the bid whisper
function Bidding:HandleBidWhisper( event, message, unitname )

	if message == "Your bid has been accepted!" then return end

	if not UnitInRaid( unitname ) then return end
	
	-- Parse message
	local item = AspireML:ParseItem(message, true)
	
	-- couldn't load information for item, queue it
	if item == -1 then		
		self.bidqueue[unitname] = message;
		return;
	end	
	self.bidqueue[unitname] = nil
	
	-- Not an item
	if not item then
		if not string.find(message:lower(), "offspec") then
			return
		end
	else
		-- It was an item, but item was not parsed. The simplest would be to let it pass, can add re-check after re-click on item later?
		if(item and not item.name) then
			-- Item is probably a numeric, if the itemID was returned. Let's make sure.
			-- Then check if linked item was the same as the active bid.
			if(type(tonumber(a)) == "number" and tonumber(item) == AspireML.biditem.itemid) then
				AspireML:Whisper(unitname, "You cannot bid with the item that is being bid for. Please only link [CURRENT ITEM]");
				return
			end
		else
			-- Perform misc item checks. TODO: Could add more later.
			
			if(item.itemid == AspireML.biditem.itemid) then
				AspireML:Whisper(unitname, "You cannot bid with the item that is being bid for. Please only link [CURRENT ITEM]");
				return
			end
			-- It was an item, but slot mismatch
			if(item.slot ~= AspireML.biditem.slot) then
				local err = "You can not bid with an item that has another slot than active bid - Try again."
				
				-- Bid item is a weapon, and so was item link. Continue
				-- Note: This is for items such as 2hs where bid is 1h etc. Caster exception mostly.
				if (AspireML.biditem.isweapon and item.isweapon) then
					err = nil
				end
				-- Bid item is a token. Continue
				if (AspireML.biditem.istoken) then
					err = nil
				end
				
				if (err) then
					AspireML:Whisper(unitname, err);
					return
				end
			end
		end
	end
	
	AspireML:Whisper( unitname, "Your bid has been accepted!" );
	SendChatMessage(unitname..": "..message, "OFFICER", nil)
	
	local entry = {}
	entry.player = unitname
	entry.message = message
	table.insert( AspireML.bids, entry )
	
	self:SendMessage( "AspireML_UpdateBids", unitname, message );
	
	
end

function Bidding:ListBids( )
	
	if not AspireML.bids[1] then
		AspireML:Print( "No bids or rolls available." );
		return
	end
	
	if AspireML.mode == "bid" then
		SendChatMessage( "*** Current Bids: ***", "OFFICER", nil)
	elseif AspireML.mode == "roll" then 
		SendChatMessage( "*** Current Rolls: ***", "OFFICER", nil)
	end
	
	for _, bid in pairs( AspireML.bids ) do
		SendChatMessage( "- " .. bid.player .. ": " .. bid.message, "OFFICER", nil)
	end
	
end

function Bidding:StartRoll( arg1, arg2 )

	-- reset state
	Bidding:CloseActiveStates()

	-- open
	AspireML.biditem = AspireML:ParseItem(arg2)
	AspireML.mode = "roll";
	
	if AspireML.masterlooter then
	
		SendChatMessage( "Roll for: " .. AspireML.biditem.link, "RAID", nil);
		self:RegisterEvent( "CHAT_MSG_SYSTEM", "HandleRoll" )
		
	end
end

function Bidding:HandleRoll( arg1, arg2 )

	-- parse rolls
	local _,_,unitname = string.find(arg2, "(.*) rolls %d+ %(1%-100%)");
	local _,_,roll = string.find(arg2, ".* rolls (%d+) %(1%-100%)");
		
	if unitname and roll then	

		-- check for double rolls
		for _, bid in pairs( AspireML.bids ) do
			if bid.player == unitname then
				AspireML:Whisper( unitname, "You already have rolled once!" );			
				return
			end
		end
	
		AspireML:Whisper( unitname, "Your roll on " .. AspireML.biditem.link .. " has been accepted!");			
				
		local entry = {}
		entry.player = unitname
		entry.message = roll
		table.insert( AspireML.bids, entry )
		table.sort(AspireML.bids, function(a,b) return AspireML:SortRolls(a,b) end);
		
		self:SendMessage( "AspireML_UpdateBids", unitname, roll );
	end
end


function Bidding:StartRaidRoll( arg1, arg2 )

	local members = GetNumRaidMembers();
	
	-- no need to roll
	if members <= 1 then 
		AspireML:Print( "Not enough members for a raidroll" )
		return
	end
	
	-- reset state
	Bidding:CloseActiveStates()

	-- open
	AspireML.biditem = AspireML:ParseItem(arg2)
	AspireML.mode = "raidroll";
	
	SendChatMessage( "Raidrolling: " .. AspireML.biditem.link, "RAID", nil);
	self:RegisterEvent( "CHAT_MSG_SYSTEM", "HandleRaidRoll" )
	
	-- remember candidates
	AspireML.candidates = {}
	for i = 1, members do
		local candidate = {}
		candidate["unitname"] = UnitName( "RAID" .. i );
		candidate["roll"] = i;
		table.insert(AspireML.candidates, candidate);		
		--AspireML:Whisper( candidate["unitname"], "You are number "..i.." on raid rolls");
	end

	self:ScheduleTimer("HandleDelayedRoll", 0.5)
end

function Bidding:HandleDelayedRoll( )

	local members = GetNumRaidMembers();
	RandomRoll(1, members);
	
end


function Bidding:HandleRaidRoll( arg1, arg2 )

	-- parse rolls
	local _,_,roll = string.find(arg2, AspireML.PLAYERNAME .. " rolls (%d+) ");	
		
	if roll then	

		for index, candidate in pairs( AspireML.candidates ) do
		
			if candidate.roll == tonumber( roll ) then
				SendChatMessage( "Winner is: "..candidate.unitname, "RAID", nil )
				AspireML:Handout(AspireML.biditem.string, candidate.unitname)
			end	
			AspireML.candidates[index] = nil;
		end
		
		AspireML.candidates = nil;
		self:UnregisterEvent( "CHAT_MSG_SYSTEM" )
	end
	
end

-- Reset the table and disable any listeners
function Bidding:CloseActiveStates( )

	-- clear current bids
	for index, bid in pairs( AspireML.bids ) do AspireML.bids[index] = nil end

	-- unregister events
	self:UnregisterEvent("CHAT_MSG_SYSTEM")	
	self:UnregisterEvent("CHAT_MSG_WHISPER");	
	
	-- notify the bids list has changes
	self:SendMessage( "AspireML_UpdateBids" );	
end

function Bidding:CloseBid( )
	
	-- rolls
	if AspireML.masterlooter and AspireML.mode == "roll" then
		self:UnregisterEvent("CHAT_MSG_SYSTEM")		
		
		if AspireML.bids[1] then
			SendChatMessage( "Rolling closed. Winner is: "..AspireML.bids[1].player, "RAID", nil)
		else
			SendChatMessage( "Rolling closed. No winner.", "RAID", nil)
		end
	
	-- bids
	elseif AspireML.masterlooter and AspireML.mode == "bid" then
		self:UnregisterEvent("CHAT_MSG_WHISPER");
		SendChatMessage( "Bidding Closed", "RAID", nil)
	else
		--self:Print( "bug: unknown bid mode" );
	end
	
	-- empty table
	for index, bid in pairs( AspireML.bids ) do	AspireML.bids[index] = nil end
	
	-- remove item
	AspireML.biditem = nil	
	
	-- reset mode
	AspireML.mode = nil
	
	self:SendMessage( "AspireML_UpdateBids" );
end





